################################# BuildImage ###################################
$ver = "180401 2018-05-02"
#############################################################################

################################# MyTrapScript Start ######################
Trap
{
    Write-Error "ERROR : Script Execution exception"
    Write-Error $_.Exception.Message
    exit
}
################################# MyTrapScript End ########################

################################# MyInvokeExpr Start ######################
function MyInvokeExpr
($expr)
{
    Write-Host ">>>> $expr"
    Invoke-Expression $expr
}
################################# MyInvokeExpr End ########################

################################ Get-ArchitectureFromInt Start ##################
function Get-ArchitectureFromInt
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)][UInt32]$imagearch
)
    switch($imagearch)
    {
        0 { $a = "x86" ; break }
        5 { $a = "arm" ; break }
        6 { $a = "ia64" ; break }
        9 { $a = "x64" ; break }
        11 { $a = "neutral" ; break }
        default { $a = "Unknown" }
    }
    return $a
}
################################ Get-ArchitectureFromInt End ####################

############################### Get-LanguageFontsPackage Start ##################
function Get-LanguageFontsPackage
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)][string]$langpak
)
	switch($langpak)
	{
        "am-et"             { $font = "Fonts-Ethi" ; break }
        "ar-sa"               { $font = "Fonts-Arab" ; break }
        "ar-sy"               { $font = "Fonts-Syrc" ; break }
        "as-in"               { $font = "Fonts-Beng" ; break }
        "bn-bd"            { $font = "Fonts-Beng" ; break }
        "bn-in"              { $font = "Fonts-Beng" ; break }
        "chr-cher-us"   { $font = "Fonts-Cher" ; break }
        "fa-ir"                { $font = "Fonts-Arab" ; break }
        "gu-in"              { $font = "Fonts-Gujr" ; break }
        "he-il"               { $font = "Fonts-Hebr" ; break }
        "hi-in"               { $font = "Fonts-Deva" ; break }
        "ja-jp"               { $font = "Fonts-Jpan" ; break }
        "km-kh"            { $font = "Fonts-Khmr" ; break }
        "kn-in"              { $font = "Fonts-Knda" ; break }
        "kok-in"           { $font = "Fonts-Deva" ; break }
        "ko-kr"             { $font = "Fonts-Kore" ; break }
        "ku-arab-iq"    { $font = "Fonts-Arab" ; break }
        "lo-la"              { $font = "Fonts-Laoo" ; break }
        "ml-in"             { $font = "Fonts-Mlym" ; break }
        "mr-in"            { $font = "Fonts-Deva" ; break }
        "ne-np"           { $font = "Fonts-Deva" ; break }
        "or-in"             { $font = "Fonts-Orya" ; break }
        "pa-arab-pk"  { $font = "Fonts-Arab" ; break }
        "pa-in"            { $font = "Fonts-Guru" ; break }
        "prs-af"           { $font = "Fonts-Arab" ; break }
        "sd-arab-pk"  { $font = "Fonts-Arab" ; break }
        "si-lk"              { $font = "Fonts-Sinh" ; break }
        "syr-sy"           { $font = "Fonts-Syrc" ; break }
        "ta-in"             { $font = "Fonts-Taml" ; break }
        "te-in"             { $font = "Fonts-Telu" ; break }
        "th-th"             { $font = "Fonts-Thai" ; break }
        "ti-et"              { $font = "Fonts-Ethi" ; break }
        "ug-cn"           { $font = "Fonts-Arab" ; break }
        "ur-pk"            { $font = "Fonts-Arab" ; break }
        "zh-cn"            { $font = "Fonts-Hans" ; break }
        "zh-tw"           { $font = "Fonts-Hant" ; break }
        default            { $font = "None" }
    }
    return $font
}
############################## Get-LanguageFontsPackage End ######################

########################### Select-LanguageInterfacePacks Start ##################
function Select-LanguageInterfacePacks
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)][string]$langname
)
    switch ($langname) {
		"af-za"             { $lips = "en-us" ; break }
        "sq-al"             { $lips = "en-us" ; break }
        "am-et"           { $lips = "en-us" ; break }
        "hy-am"          { $lips = "en-us" ; break }
        "as-in"             { $lips = "en-us" ; break }
        "az-latn-az"    { $lips = "en-us" ; break }
        "bn-bd"          { $lips = "en-us" ; break }
        "eu-es"           { $lips = "es-es" ; break }
        "be-by"           { $lips = "ru-ru" ; break }
        "bn-in"            { $lips = "en-us" ; break }
        "bs-latn-ba"   { $lips = "en-us" ; break }
        "ca-es"            { $lips = "es-es" ; break }
        "ku-arab-iq"   { $lips = "en-us" ; break }
        "chr-cher-us" { $lips = "en-us" ; break }
        "prs-af"           { $lips = "en-us" ; break }
        "fil-ph"            { $lips = "en-us" ; break }
        "gl-es"            { $lips = "es-es" ; break }
        "ka-ge"           { $lips = "en-us" ; break }
        "gu-in"            { $lips = "en-us" ; break }
        "ha-latn-ng"   { $lips = "en-us" ; break }
        "hi-in"             { $lips = "en-us" ; break }
        "is-is"              { $lips = "en-us" ; break }
        "ig-ng"            { $lips = "en-us" ; break }
        "id-id"             { $lips = "en-us" ; break }
        "ga-ie"            { $lips = "en-us" ; break }
        "xh-za"           { $lips = "en-us" ; break }
        "zu-za"            { $lips = "en-us" ; break }
        "kn-in"            { $lips = "en-us" ; break }
        "kk-kz"            { $lips = "en-us" ; break }
        "km-kh"          { $lips = "en-us" ; break }
        "quc-latn-gt" { $lips = "es-mx" ; break }
        "rw-rw"          { $lips = "en-us" ; break }
        "sw-ke"          { $lips = "en-us" ; break }
        "kok-in"          { $lips = "en-us" ; break }
        "ky-kg"           { $lips = "ru-ru" ; break }
        "lo-la"             { $lips = "en-us" ; break }
        "lb-lu"             { $lips = "fr-fr" ; break }
        "mk-mk"         { $lips = "en-us" ; break }
        "ms-bn"          { $lips = "en-us" ; break }
        "ms-my"         { $lips = "en-us" ; break }
        "ml-in"             { $lips = "en-us" ; break }
        "mt-mt"          { $lips = "en-us" ; break }
        "mi-nz"            { $lips = "en-us" ; break }
        "mr-in"            { $lips = "en-us" ; break }
        "mn-mn"        { $lips = "en-us" ; break }
        "ne-np"           { $lips = "en-us" ; break }
        "nn-no"          { $lips = "nb-no" ; break }
        "or-in"            { $lips = "en-us" ; break }
        "fa-ir"              { $lips = "en-us" ; break }
        "pa-in"            { $lips = "en-us" ; break }
        "pa-arab-pk"  { $lips = "en-us" ; break }
        "quz-pe"         { $lips = "es-mx" ; break }
        "gd-gb"          { $lips = "en-us" ; break }
        "sr-cyrl-ba"     { $lips = "sr-latn-rs" ; break }
        "sr-cyrl-rs"      { $lips = "sr-latn-rs" ; break }
        "nso-za"         { $lips = "en-us" ; break }
        "tn-za"            { $lips = "en-us" ; break }
        "ad-arab-pk" { $lips = "en-us" ; break }
        "si-lk"              { $lips = "en-us" ; break }
        "tg-cyrl-tj"     { $lips = "ru-ru" ; break }
        "ta-in"             { $lips = "en-us" ; break }
        "tt-ru"             { $lips = "ru-ru" ; break }
        "te-in"             { $lips = "en-us" ; break }
        "ti-et"              { $lips = "en-us" ; break }
        "tk-tm"            { $lips = "ru-ru" ; break }
        "ur-pk"            { $lips = "en-us" ; break }
        "ug-cn"            { $lips = "zh-cn" ; break }
        "uz-latn-uz"     { $lips = "en-us" ; break }
        "ca-es-valencia" { $lips = "es-es" ; break }
        "vi-vn"              { $lips = "en-us" ; break }
        "cy-gb"            { $lips = "en-us" ; break }
        "wo-sn"           { $lips = "fr-fr" ; break }
        "yo-ng"           { $lips = "en-us" ; break }
        Default            { $lips = "None" }
    }
    return $lips
}
############################ Select-LanguageInterfacePacks End ###################

################################ Get-DriveLetterFromPath Start ###################
function Get-DriveLetterFromPath
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] 
[string]$Path,
[switch]$Resolve
)
    Try
    {
        if(Split-Path -Path $Path -IsAbsolute)
        {
            Split-Path -Path $Path -Qualifier -Resolve:$Resolve -ErrorAction Stop
        }
    }
    Catch
    {
        Write-Host "Failed to get drive letter. Details : $_"
    }
}
################################ Get-DriveLetterFromPath End #################

################################ Dism-MountWimImage Start ###################
function Dism-MountWimImage
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] [string]$img_file,
[parameter(mandatory=$true)] [string]$mount_dir
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-MountWimImage Start  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "

    $dismcmd = "DISM /Mount-Image /ImageFile:`"$img_file`" /MountDir:`"$mount_dir`" /Index:1 "
    MyInvokeExpr $dismcmd
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-MountWimImage End  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "
}
################################ Dism-MountWimImage End #################

################################ Dism-UnmountWimImage Start ###################
function Dism-UnmountWimImage
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] [string]$mount_dir,
[parameter(mandatory=$true)] [string]$paramet
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-UnmountWimImage Start  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "

    $dismcmd = "DISM /Unmount-Image /Mountdir:`"$mount_dir`" /$paramet"
    MyInvokeExpr $dismcmd
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-UnmountWimImage End  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "
}
################################ Dism-UnmountWimImage End #################

################################ Dism-ExportWimImage Start ###################
function Dism-ExportWimImage
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] [string]$source_file,
[parameter(mandatory=$true)] [string]$destination_file
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-ExportWimImage Start  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "

    $dismcmd = "DISM /Export-Image /SourceImagefile:`"$source_file`" /SourceIndex:1 /DestinationImageFile:`"$destination_file`" "
    MyInvokeExpr $dismcmd
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-ExportWimImage End  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "
}
################################ Dism-ExportWimImage End #################

################################ Dism-SplitWimImage Start ###################
function Dism-SplitWimImage
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] [string]$source_file,
[parameter(mandatory=$true)] [string]$split_file,
[parameter(mandatory=$true)] [string]$file_size
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-SplitWimImage Start  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "

    $dismcmd = "DISM /Split-Image /ImageFile:`"$source_file`" /SWMFile:`"$split_file`" /FileSize:$file_size"
    MyInvokeExpr $dismcmd
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-SplitWimImage End  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "
}
################################ Dism-SplitWimImage End #################

################################ Dism-CleanupWimImage Start ###################
function Dism-CleanupWimImage
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] [string]$mount_dir
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-CleanupWimImage Start  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "

    $dismcmd = "DISM /Image:`"$mount_dir`" /Cleanup-Image /StartComponentCleanup /ResetBase"
    MyInvokeExpr $dismcmd
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Dism-CleanupWimImage End  <<<<<<<<<<<<<<<<<<<<<<<" 
    Write-Host " "
}
################################ Dism-CleanupWimImage End #################

############################ Add-AppxPackages Statt ###########################
function Add-AppxPackages 
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] [string]$image_path,
[parameter(mandatory=$true)] [string]$appx_update_base,
[parameter(mandatory=$true)] [string]$imagearch
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>>>>> Add-AppxPackages Start <<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
    
    $appxpacks = Get-ChildItem -path $appx_update_base -filter *.appx
    
    if(($imagearch -eq "arm") -or ($imagearch -eq "x86"))
    {
        foreach ($appx in $appxpacks)
        {
            if ($appx.Name -match $imagearch)
            {
                $appxname = $appx_update_base + "\" + $appx.Name
                $deppackage += "/DependencyPackagePath:`"$appxname`" "
            }
        }
    }
    elseif(($imagearch -eq "x64"))
    {
        foreach ($appx in $appxpacks)
        {
            if (($appx.Name -match $imagearch) -or ($appx.Name -match "x86"))
            {
                $appxname = $appx_update_base + "\" + $appx.Name
                $deppackage += "/DependencyPackagePath:`"$appxname`" "
            }
        }
    }
    else
    {
        Write-Error "Unknown system architecture"
        exit;
    }
    
    $packages = Get-ChildItem -path $appx_update_base -filter *.appxbundle
    foreach ($pack in $packages)
    {
        $pack_name = $pack.Name
        $lic_name = $pack_name -replace ".appxbundle", ".xml"
        $pack_path = $appx_update_base + "\" + $pack_name
        $lic_path = $appx_update_base + "\" + $lic_name
        Write-Host "Processing Package $pack_name"
        $dismcmd = "DISM /Image:`"$image_path`" /Add-ProvisionedAppxPackage /PackagePath:`"$pack_path`" /LicensePath:`"$lic_path`" $DepPackage"
        MyInvokeExpr $dismcmd
        Write-Host " "
    }
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>>>>> Add-AppxPackages End <<<<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
}
############################## Add-AppxPackages End ###########################

############################ Add-OfficeAppxPackages Statt #########################
function Add-OfficeAppxPackages
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] [string]$image_path,
[parameter(mandatory=$true)] [string]$appx_update_base,
[parameter(mandatory=$true)] [string]$appxtype
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>>>>> Add-OfficeAppxPackages Start <<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "

    $shared_pack_path = "/PackagePath:`"$appx_update_base\Shared.PreinstallKit\Shared.appxbundle`" /LicensePath:`"$appx_update_base\Shared.PreinstallKit\Shared_License1.xml`" "
    $excel_pack_path = "/OptionalPackagePath:`"$appx_update_base\Excel.PreinstallKit\Excel.appxbundle`" /LicensePath:`"$appx_update_base\Excel.PreinstallKit\Excel_License1.xml`" "
    $word_pack_path = "/OptionalPackagePath:`"$appx_update_base\Word.PreinstallKit\Word.appxbundle`" /LicensePath:`"$appx_update_base\Word.PreinstallKit\Word_License1.xml`" "
    $ppt_pack_path = "/OptionalPackagePath:`"$appx_update_base\PowerPoint.PreinstallKit\PowerPoint.appxbundle`" /LicensePath:`"$appx_update_base\PowerPoint.PreinstallKit\PowerPoint_License1.xml`" "
    $access_pack_path = "/OptionalPackagePath:`"$appx_update_base\Access.PreinstallKit\Access.appxbundle`" /LicensePath:`"$appx_update_base\Access.PreinstallKit\Access_License1.xml`" "
    $outlook_pack_path = "/OptionalPackagePath:`"$appx_update_base\Outlook.PreinstallKit\Outlook.appxbundle`" /LicensePath:`"$appx_update_base\Outlook.PreinstallKit\Outlook_License1.xml`" "
    $publisher_pack_path = "/OptionalPackagePath:`"$appx_update_base\Publisher.PreinstallKit\Publisher.appxbundle`" /LicensePath:`"$appx_update_base\Publisher.PreinstallKit\Publisher_License1.xml`" "

    switch($appxtype)
	{
        "OfficeProfessional" {
            $appx_office_pack = $shared_pack_path + $excel_pack_path + $word_pack_path + $ppt_pack_path + $access_pack_path + $outlook_pack_path + $publisher_pack_path
        }
        "O365Personal" {
            $appx_office_pack = $shared_pack_path + $excel_pack_path + $word_pack_path + $ppt_pack_path + $access_pack_path + $outlook_pack_path + $publisher_pack_path
        }
        "O365Home" {
            $appx_office_pack = $shared_pack_path + $excel_pack_path + $word_pack_path + $ppt_pack_path + $access_pack_path + $outlook_pack_path + $publisher_pack_path
        }
        "OfficeHomeandStudent" {
            $appx_office_pack = $shared_pack_path + $excel_pack_path + $word_pack_path + $ppt_pack_path
        }
        "OfficeHomeandBusiness" {
            $appx_office_pack = $shared_pack_path + $excel_pack_path + $word_pack_path + $ppt_pack_path + $outlook_pack_path
        }
        "OfficeProfessionalAcademic" {
            $appx_office_pack = $shared_pack_path + $excel_pack_path + $word_pack_path + $ppt_pack_path + $outlook_pack_path + $publisher_pack_path
        }
        "OfficePersonal" {
            $appx_office_pack = $shared_pack_path + $excel_pack_path + $word_pack_path + $outlook_pack_path
        }
        default {
            Write-Error "No Office types are found to be installed"
            exit;
        }
    }

    $dismcmd = "DISM /Image:`"$image_path`" /Add-ProvisionedAppxPackage $appx_office_pack "
    MyInvokeExpr $dismcmd

    Write-Host " "
    Write-Host ">>>>>>>>>>>>>>>> Add-OfficeAppxPackages End <<<<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
}
############################## Add-OfficeAppxPackages End #########################

############################## Add-ImageDrivers Start #############################
function Add-ImageDrivers
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] [string]$image_path,
[parameter(mandatory=$true)] [string]$inf_drivers
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Add-ImageDrivers START <<<<<<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
    
    if (Test-Path $inf_drivers)
    {
        Write-Host "Checking for drivers in [$inf_drivers]"
        
        $ddd = (Get-ChildItem $inf_drivers) | Measure-Object
        if ($ddd.Count -gt 0)
        {
            $dismcmd = "DISM /Image:`"$image_path`" /Add-Driver /Driver:`"$inf_drivers`" /Recurse"
            MyInvokeExpr $dismcmd
            Write-Host " "
        }
        else
        {
            Write-Host "INF_Drivers folder is empty.  Skipping..."
        }
    }
    else
    {
        Write-Host "INF_Drivers folders not found.  Skipping..."
    }
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Add-ImageDrivers End <<<<<<<<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
}
############################# Add-ImageDrivers End ##############################
 
############################# Update-ImageMsu Start #############################
function Update-ImageMsu
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] [string]$image_path,
[parameter(mandatory=$true)] [string]$msu_path
) 
    Write-Host " "
    Write-Host ">>>>>>>>>>>> Update-ImageMsu START <<<<<<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
    
    if (Test-Path $msu_path)
    {
        $msuCount = ((Get-ChildItem $msu_path) | Measure-Object ).Count
        Write-Host " "
        Write-Host "Found [$msuCount] .msu file in [$msu_path]"
        Write-Host " "
        $msu = (Get-ChildItem $msu_path)
        if ($msu.Count -gt 0)
        {
            foreach($a in $msu)
            {
                $updateMsu = $msu_path + "\" + $a
                $updateMsus += "/PackagePath:`"$updateMsu`" "
            }
            
            $dismcmd = "DISM /Image:`"$image_path`" /Add-Package $updateMsus"
            MyInvokeExpr $dismcmd
            Write-Host " "
        }
        else
        {
            Write-Host "Msu folder is empty.  Skipping..."
        }
    }
    else
    {
        Write-Host "Msu folders not found.  Skipping..."
    }
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Update-ImageMsu End <<<<<<<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
}
############################# Update-ImageMsu End ###############################

############################# Remove-LanguagePacks Start ########################
function Remove-LanguagePacks 
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] $lang_remove,
[parameter(mandatory=$true)] [string]$imagepath
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Remove-LanguagePacks START <<<<<<<<<<<<<<<<<<<"
    Write-Host " "
    
    if($lang_remove.Count -gt 0)
    {
        foreach($lang_pkg in $lang_remove)
        {
            $lang_pkgs += "/PackageName:`"$lang_pkg`" "
        }
        
        $dismcmd = "DISM /Image:`"$imagepath`" /Remove-Package $lang_pkgs"
        MyInvokeExpr $dismcmd
        Write-Host " "
    }
    else
    {
        Write-Host "Remove language packs is null, skip ..."
    }
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Remove-LanguagePacks End <<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
}
############################# Remove-LanguagePacks End ##########################

############################## Add-ReLanguagePacks Start ##########################
function Add-ReLanguagePacks 
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] $lang_to_add,
[parameter(mandatory=$true)] [string]$re_mnt_path,
[parameter(mandatory=$true)] [string]$winpe_ocs_root
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Add-ReLanguagePacks START <<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
    
    # Validate that all language packs is available
    foreach ($lang in $lang_to_add)
    {
        $langpacks = [string]::Empty
        $temlang = $lang.ToUpper()
        $langpack = $winpe_ocs_root + "\WinPE-FontSupport-" + $temlang + ".cab"
        if(Test-Path $langpack)
        {
            $langpacks += "/PackagePath:`"$langpack`" "
        }
        $langpack = $winpe_ocs_root + "\WinPE-Speech-TTS-" + $temlang + ".cab"
        if(Test-Path $langpack)
        {
            $langpacks += "/PackagePath:`"$langpack`" "
        }
        
        $langpack_path = $winpe_ocs_root + "\" + $lang + "\"
        if (Test-Path $langpack_path)
        {
            $packlang = $langpack_path + "lp.cab"
            $dismcmd = "DISM /Image:`"$re_mnt_path`" /Add-Package /PackagePath:`"$packlang`" "
            MyInvokeExpr $dismcmd
            Write-Host " "
            
            $langpack = $langpack_path + "WinPE-EnhancedStorage_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-Rejuv_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-Scripting_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-SecureStartup_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-SRT_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-WDS-Tools_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-WMI_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-StorageWMI_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-HTA_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-Narrator_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-SRH_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-WiFi_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-ATBroker_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-AudioCore_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $langpack = $langpack_path + "WinPE-AudioDrivers_" + $lang + ".cab"
            $langpacks += "/PackagePath:`"$langpack`" "
            
            $dismcmd = "DISM /Image:`"$re_mnt_path`" /Add-Package  $langpacks"
            MyInvokeExpr $dismcmd
            Write-Host " "
        }
        else
        {
            Write-Error "Requested Langpack path not found : $langpack_path"
            exit;
        }
    }
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Add-ReLanguagePacks End <<<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
}
############################### Add-ReLanguagePacks End ###########################

############################## Add-LanguagePacks Start ##########################
function Add-LanguagePacks 
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] $lang_to_add,
[parameter(mandatory=$true)] $lang_ip_add,
[parameter(mandatory=$true)] [string]$imagepath,
[parameter(mandatory=$true)] [string]$langpacks_path,
[parameter(mandatory=$true)] [string]$imagearch
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Add-LanguagePacks START <<<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
    
    # Validate that all language packs is available
    foreach ($lang in $lang_to_add)
    {
        $langpack = $langpacks_path + "\Microsoft-Windows-Client-Language-Pack_" + $imagearch + "_" + $lang +".cab"
        if (Test-Path $langpack)
        {
            $dismcmd = "DISM /Image:`"$imagepath`" /Add-Package /PackagePath:`"$langpack`" "
            MyInvokeExpr $dismcmd
            Write-Host " "
        }
        else
        {
            Write-Error "Langpack does not exist : $langpack"
            exit;
        }
    }

    foreach ($lip in $lang_ip_add) 
    {
        $lipack = $langpacks_path + "\Microsoft-Windows-Client-Language-Interface-Pack_" + $imagearch + "_" + $lip +".cab"
        if (Test-Path $lipack)
        {
            $dismcmd = "DISM /Image:`"$imagepath`" /Add-Package /PackagePath:`"$lipack`" "
            MyInvokeExpr $dismcmd
            Write-Host " "
        }
        else
        {
            Write-Error "Lang interface pack does not exist : $lipack"
            exit;
        }
    }
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Add-LanguagePacks End <<<<<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
}
############################### Add-LanguagePacks End ###########################

############################ Add-LanguageComponents Start #######################
function Add-LanguageComponents 
{
[cmdletbinding()] 
param( 
[parameter(mandatory=$true)] $lang_to_add,
[parameter(mandatory=$true)] $lang_ip_add,
[parameter(mandatory=$true)] [string]$imagepath,
[parameter(mandatory=$true)] [string]$langcomponents
)
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Add-LanguageComponents START <<<<<<<<<<<<<<<<<<<"
    Write-Host " "
    
    $componentsCount = ((Get-ChildItem $langcomponents) | Measure-Object ).Count
    
    if ($componentsCount -gt 0)
    {
        Write-Host "Found [$componentsCount] file in [$langcomponents]"
        
        [System.Collections.ArrayList] $lang_com = @()
        foreach ($lang_to in $lang_to_add)
        {
            $lang_com.Add($lang_to)
        }
        foreach ($lang_ip in $lang_ip_add)
        {
            $lang_com.Add($lang_ip)
        }
        
        $packages = Get-ChildItem -path $langcomponents -filter *.cab
        
        foreach ($lang in $lang_com)
        {
            [string] $fontPack = Get-LanguageFontsPackage($lang)
        
            $cabPacks = [string]::Empty
            foreach ($pack in $packages)
            {
                $component = $pack.Name
                if (($component -match "-Basic-" + $lang + "-") -or ($component -match "-Speech-" + $lang + "-") -or ($component -match "-TextToSpeech-" + $lang + "-") -or ($component -match "-Handwriting-" + $lang + "-") -or ($component -match $fontPack))
                {
                    $cabPack=$langcomponents + "\" + $component
                    $cabPacks += "/PackagePath:`"$cabPack`" "
                }
            }
            
            $dismcmd = "DISM /Image:`"$imagepath`" /Add-Package $cabPacks"
            MyInvokeExpr $dismcmd
            Write-Host " "
          
            Write-Host "These packages have been completed"
        }
    }
    else
    {
        Write-Host "Not found file in [$langcomponents]. Skipping..."
    }
    
    Write-Host " "
    Write-Host ">>>>>>>>>>>>> Add-LanguageComponents End <<<<<<<<<<<<<<<<<<<<<"
    Write-Host " "
}
############################ Add-LanguageComponents End #########################

############################ Environment settings ###############################
# Get the ID and security principal of the current user account
 $myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
 $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
 
 # Get the security principal for the Administrator role
 $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
 
 # Check to see if we are currently running "as Administrator"
if ($myWindowsPrincipal.IsInRole($adminRole))
{
    # We are running "as Administrator" - so change the title to indicate this
    $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)  $ver"
    #clear-host
}
else
{
    Write-Error "You must run the script as administrator"
    exit
}

#################################################################################
# Run your code that needs to be elevated here
#################################################################################

Write-Host "******************************************************************"
Write-Host "                        Build Image For Windows10 "
Write-Host "                          $ver "
Write-Host "******************************************************************"

#################################################################################
# Define default binary locations
#############################################################################
$script_base_path = Split-Path -Parent (Split-Path -Parent ($MyInvocation.MyCommand.Path))
$baseos_path = $script_base_path + "\BaseOS"
$sources_path = $script_base_path + "\Sources"
$scripts_path = $script_base_path + "\Scripts"
$baseos_image = $baseos_path + "\Install.wim"

Write-Host "Base OS Path : $baseos_path"
Write-Host "Source File Path : $sources_path"
Write-Host "Source Image : $baseos_image "
Write-Host " "

#################################################################################
#                   Check for script dependancies
#################################################################################
$start_time = (Get-Date)

if (-not (Test-Path $baseos_image))
{
    Write-Error "Install.wim not found in : [$baseos_path]"
    exit
}
Write-Host "Install.wim found in : [$baseos_path]"

$image_info = Get-WindowsImage -ImagePath $baseos_image -Index 1
$image_edition = $image_info.EditionId

Write-Host "Architecture : " + $image_info.Architecture
Write-Host "Languages : " + $image_info.Languages
Write-Host "ImageName : " + $image_info.ImageName
Write-Host "EditionId :  + $image_edition"

$arch = Get-ArchitectureFromInt([UInt32]$image_info.Architecture)
if (($arch -ne "x86") -and ($arch -ne "x64")) 
{
    Write-Error "Found OS image architecture is not supported "
    exit
}

if ([Environment]::Is64BitOperatingSystem)
{
    $dism_path = $scripts_path + "\DISM\amd64"
}
else
{
    $dism_path = $scripts_path + "\DISM\x86"
} 

if (-not (Test-Path $dism_path))
{
    Write-Error "Not found [$dism_path]"
    exit
}

$appx_update_base = $sources_path + "\UniversalAppsPacks\Appx"
$desktop_office_update_base = $sources_path + "\UniversalAppsPacks\DesktopOffice" 
$mobile_office_update_base = $sources_path + "\UniversalAppsPacks\MobileOffice" 
$update_msu_os = $sources_path + "\WindowsUpdatePacks\" + $arch

if ((-not (Test-Path $appx_update_base)) -or (-not (Test-Path $desktop_office_update_base)) -or (-not (Test-Path $mobile_office_update_base)) -or (-not (Test-Path $update_msu_os)))
{
    Write-Error "Clamp at least one the following folders does not exist :"
    Write-Error "[$appx_update_base]"
	Write-Error "[$desktop_office_update_base]"
    Write-Error "[$mobile_office_update_base]"
    Write-Error "[$update_msu_os]"
    exit
}

$langpack_os = $sources_path + "\MultiLangPacks\" + $arch + "\langpacks"
$langpack_re = $sources_path + "\MultiLangPacks\" + $arch + "\WinPE_OCs"
$langcomponents_os = $sources_path + "\MultiLangPacks\" + $arch + "\FODs"

if ((-not (Test-Path $langpack_os)) -or (-not (Test-Path $langpack_re)) -or (-not (Test-Path $langcomponents_os)))
{
    Write-Error "Clamp at least one the following folders does not exist :"
    Write-Error "[$langpack_os]"
    Write-Error "[$langpack_re]"
    Write-Error "[$langcomponents_os]"
    exit
}

$inf_drivers_os = $sources_path + "\WindowsDriversPacks\" + $arch + "\OS"
$inf_drivers_re = $sources_path + "\WindowsDriversPacks\" + $arch + "\WinRE"

if ((-not (Test-Path $inf_drivers_os)) -or (-not (Test-Path $inf_drivers_re)))
{
    Write-Error "Clamp at least one the following folders does not exist :"
    Write-Error "[$inf_drivers_os]"
    Write-Error "[$inf_drivers_re]"
    exit
}

Write-Host "DISM root found in : [$dism_path]"
Write-Host "App update root found in : [$appx_update_base]"
Write-Host "Office update root found in : [$desktop_office_update_base]"
Write-Host "Office update root found in : [$mobile_office_update_base]"
Write-Host "OS lang package root found in : [$langpack_os]"
Write-Host "RE lang package root found in : [$langpack_re]"
Write-Host "OS lang components root found in : [$langcomponents_os]"
Write-Host "OS update msu root found in : [$update_msu_os]"
Write-Host "OS inf drivers root found in : [$inf_drivers_os]"
Write-Host "RE inf drivers root found in : [$inf_drivers_re]"
Write-Host " "
Write-Host "Check folders required have been completed"
Write-Host " "

$env:path = $dism_path
Write-Host "Add environment path $dism_path"
Write-Host " "

#################################################################################
if ($args.Count -ne 2)
{
    Write-Host " "
    Write-Host "ERROR : Input parameter Error!"
    Write-Host " "
    exit
}

[System.Collections.ArrayList] $inputs = @()
foreach ($aa in $args[0])
{
    foreach ($bb in ($aa.Split(", ")))
    {
        if (-not ([string]::IsNullOrWhiteSpace($bb)))
        {
            $inputs.Add($bb.ToLower())
        }
    }
}

$office_type = $args[1]

$target_langs = $inputs.Clone()

Write-Host "Image target language : $target_langs"
Write-Host " "

[System.Collections.ArrayList] $lipacks = @()
foreach ($input in $inputs)
{
    [string]$outputs = Select-LanguageInterfacePacks($input)
    if ($outputs -ne "None")
    {
        $lipacks.Add($input)
        $target_langs.Remove($input)

        if($target_langs -notcontains $outputs)
        {
             $target_langs.Add($outputs)
        }
    }
}

Write-Host "Processing language : $target_langs"
Write-Host "Others add language : $lipacks"
Write-Host " "

foreach ($ll in $target_langs)
{
    Write-Host "Checking for language pack : [$langpack_re\$ll]"
    if (-not (Test-Path "$langpack_re\$ll"))
    {
        Write-Error "Win RE Language Pack [$ll] NOT FOUND !"
        exit 
    }
    Write-Host " "
}

#################################################################################
$os_mnt_path = $baseos_path +"\OS-Mount"
$re_mnt_path = $baseos_path + "\RE-Mount"

Write-Host "OS mount point : $os_mnt_path"
Write-Host "RE mount point : $re_mnt_path"
Write-Host " "

Write-Host "Cleanup the mount points"
Clear-WindowsCorruptMountPoint
Write-Host " "

#################################################################################
if(test-path $re_mnt_path)
{
    Dism-UnmountWimImage $re_mnt_path "Discard"
    Remove-Item -Path $re_mnt_path -Force -Recurse
}

if (test-path $os_mnt_path)
{
    Dism-UnmountWimImage $os_mnt_path "Discard"
    Remove-Item -Path $os_mnt_path -Force -Recurse
}

New-Item $os_mnt_path -itemType directory 
New-Item $re_mnt_path -itemType directory 
if ((-not (Test-Path $os_mnt_path)) -or (-not (Test-Path $re_mnt_path)))
{
    Write-Error "ERROR - Failed to create temporary mount point"
    exit
}
Write-Host "Created os mount point at : $os_mnt_path"
Write-Host "Created re mount point at : $re_mnt_path"
Write-Host " "

Write-Host "Started backup Install.wim file"
Write-Host ". . . . . . . . . ."
$backupos_image = $baseos_path + "\Install_" + $arch + "_" + $image_edition + "_bak.wim"
Copy-Item -Path $baseos_image -Destination $backupos_image -Force
Write-Host "Backup Install.wim file end"
Write-Host " "

#################################################################################
Write-Host "Mounting image ..."
Dism-MountWimImage $baseos_image $os_mnt_path
Write-Host " "

$re_wim = $os_mnt_path + "\Windows\System32\Recovery\Winre.wim"
Write-Host "Checking for Winre.wim : $re_wim"
Write-Host " "

if ( -not (Test-Path $re_wim))
{
    Write-Host "Winre.wim NOT found."
    Write-Host " "
}
else
{
    Write-Host "============== Updating WinRE And Languages  ==============="

    $re_version = ((Get-WindowsImage -ImagePath $re_wim -Index 1).Version)
    $re_minor_version = ($re_version.split("."))[3]
    Write-Host "WinRE found at : $re_wim"
    Write-Host "WinRE version is $re_version"
    Write-Host " "

    Write-Host "Mounting WinRE image ..."
    Dism-MountWimImage $re_wim $re_mnt_path
    Write-Host " "

    #################################################################################
    Write-Host "================= Update WinRE Language ===================="
    Write-Host ">> Update-WinreImageLanguage image path : [$re_mnt_path]"
    $re_packages = Get-WindowsPackage -Path $re_mnt_path

    [System.Collections.ArrayList] $re_lang_remove = @()
    [System.Collections.ArrayList] $re_lang_add = $target_langs.Clone()
    foreach($re_pkg in $re_packages)
    {
        $re_pkgname = $re_pkg.PackageName
        if ($re_pkgname -like "Microsoft-Windows-WinPE-LanguagePack-Package*") 
        {
            Write-Host ">>> Installed WinRE Language Client Pack : $re_pkgname"
            $re_pkg_split = ($re_pkgname).Split("~");
            $re_mlang = ($re_pkg_split[3]).ToLower()
            if ($re_lang_add -icontains $re_mlang)
            {
                $re_lang_add.Remove($re_mlang)
            }
            else
            {
                $re_lang_remove.Add($re_pkgname)
                foreach($re_mpkg in $re_packages)
                {
                    $re_mpkgname = $re_mpkg.PackageName
                    if (($re_mpkgname -like "WinPE*") -and ($re_mpkgname -like "*" + $re_mlang + "*")) 
                    {
                        Write-Host ">>> Installed WinRE Language Features Pack : $re_mpkgname"
                        $re_lang_remove.Add($re_mpkgname)
                    }
                }
            }
        }
    }

    Write-Host "----------------------------------- Need to add Language ---------------------------------"
    $re_lang_add
    Write-Host "------------------------------------------------------------------------------------------"
    Write-Host " "

    Write-Host "================== Remove-ReLanguagePacks =================="
    Remove-LanguagePacks $re_lang_remove $re_mnt_path
    Write-Host " "

    Write-Host "=================== Add-ReLanguagePacks ===================="
    Add-ReLanguagePacks $re_lang_add $re_mnt_path $langpack_re
    Write-Host " "

    Write-Host "=================== Inject WinRE Drivers ==================="
    Add-ImageDrivers $re_mnt_path $inf_drivers_re
    Write-Host " "

    Write-Host "Cleanup the image to reduce size"
    Dism-CleanupWimImage $re_mnt_path
    Write-Host " "

    Write-Host "Unmounting image ..."
    Dism-UnmountWimImage $re_mnt_path "Commit"
    Write-Host " "

    $tmp_wim = $re_wim + ".tmp"
    Dism-ExportWimImage $re_wim $tmp_wim
    Write-Host " "
    
    Move-Item -Path $tmp_wim -Destination $re_wim -Force
    Write-Host " "
}

if(Test-Path $re_mnt_path)
{
    Remove-Item -Path $re_mnt_path -Force
}

Write-Host "================= Updating Image Languages ================"
Write-Host ">> Update-ImageLanguage image path : [$os_mnt_path]"
$packages = Get-WindowsPackage -Path $os_mnt_path

[System.Collections.ArrayList] $lang_remove = @()
[System.Collections.ArrayList] $lang_add = $target_langs.Clone()
foreach($pkg in $packages)
{
    $pkgname = $pkg.PackageName
    if ($pkgname -like "Microsoft-Windows-Client-LanguagePack-Package*") 
    {
        Write-Host ">>> Installed Language Client Pack : $pkgname"
        $pkg_split = ($pkgname).Split("~");
        $mlang = ($pkg_split[3]).ToLower()
        if ($lang_add -icontains $mlang)
        {
            $lang_add.Remove($mlang)
        }
        else
        {
            $lang_remove.Add($pkgname)
            [string] $fontpak = Get-LanguageFontsPackage($mlang)
            foreach($mpkg in $packages)
            {
                $mpkgname = $mpkg.PackageName
                if (($mpkgname -like "Microsoft-Windows-LanguageFeatures*") -and ($mpkgname -like "*" + $mlang + "*") -and ($mpkgname -notlike "Microsoft-Windows-LanguageFeatures-Basic*")) 
                {
                    Write-Host ">>> Installed Language Features Pack : $mpkgname"
                    $lang_remove.Add($mpkgname)
                }
                if($fontpak -ne "None")
                {
                     if ($mpkgname -like $fontpak + "*")
                     {
                         Write-Host ">>> Installed Language Features Font Pack : $mpkgname"
                         $lang_remove.Add($mpkgname)
                     }
                }
            }
        }
    }
}

Write-Host "----------------------------------- Need to add Language ---------------------------------"
$lang_add
$lipacks
Write-Host "------------------------------------------------------------------------------------------"
Write-Host " "

Write-Host "=================== Remove-LanguagePacks ==================="
Remove-LanguagePacks $lang_remove $os_mnt_path
Write-Host " "

Write-Host "=================== Add-LanguagePacks ======================"
Add-LanguagePacks $lang_add $lipacks $os_mnt_path $langpack_os $arch
Write-Host " "

Write-Host "============== Add-LanguageComponentPacks =================="
Add-LanguageComponents $lang_add $lipacks $os_mnt_path $langcomponents_os
Write-Host " "

if($lang_add.Count -gt 0)
{
    Write-Host "================ Add All AppXPackages ====================="
    Add-AppxPackages $os_mnt_path $appx_update_base $arch
    Write-Host " "
}

Write-Host "******************** Office Type : $office_type ********************"
Write-Host " "
if($office_type -eq "NoneOffice")
{
    Write-Host "Do not install any Office products"
    $office_type_num = 0
    Write-Host " "
}
elseif($office_type -eq "MobileOffice")
{
    Write-Host "============ Add Mobile Office AppXPackages ==============="
    Add-AppxPackages $os_mnt_path $mobile_office_update_base $arch
    $office_type_num = 1
    Write-Host " "
}
else
{
    Write-Host "============ Add Desktop Office AppXPackages ==============="
    Add-OfficeAppxPackages $os_mnt_path $desktop_office_update_base $office_type
    $office_type_num = 2
    Write-Host " "
}

Write-Host "================== Inject Drivers  ========================"
Add-ImageDrivers $os_mnt_path $inf_drivers_os
Write-Host " "

Write-Host "=============== Updating msu for image ===================="
Update-ImageMsu $os_mnt_path $update_msu_os
Write-Host " "

Write-Host "Cleanup the image to reduce size"
Dism-CleanupWimImage $os_mnt_path
Write-Host " "

Write-Host "Gets the current date and write files"
$curr_time = Get-Date -Format "MM-dd-yyyy"
$curr_time | Out-File -Encoding ascii -FilePath "$os_mnt_path\Windows\csup.txt"
Write-Host " "

Write-Host "Mark the currently installed Office type"
$office_type_num | Out-File -Encoding ascii -FilePath "$os_mnt_path\Windows\OfficeType.txt"
Write-Host " "

$tmpsource = $os_mnt_path + "\sources"
if (Test-Path $tmpsource)
{
    Remove-Item -Path $tmpsource -Force -Recurse
}

Write-Host "Unmount image ... "
Dism-UnmountWimImage $os_mnt_path "Commit"
Write-Host " "

if (Test-Path $os_mnt_path)
{
    Remove-Item -Path $os_mnt_path -Force -Recurse
}

Write-Host "Delete temporary files during operation"
Get-ChildItem $env:TEMP | Where-Object { $_.Name -like "appxStage*" } | Remove-Item -Force -Recurse
Write-Host " "

Write-Host " Re-export to realize the space saving "
$tmp_wim = $baseos_image + ".tmp"
Dism-ExportWimImage $baseos_image $tmp_wim
Write-Host " "
 
Move-Item -Path $tmp_wim -Destination $baseos_image -Force
Write-Host " "

$wimInfo = Get-Item $baseos_image
if($wimInfo.Length -gt 4294967296)
{
    Write-Host "Found $endWim size greater than 4GB"
    $split_image = $baseos_path + "\Install.swm"
    Dism-SplitWimImage $baseos_image $split_image "4000"
    Write-Host "$baseos_image split successful"
    Write-Host " "
    Write-Host "Remove $baseos_image file"
    Remove-Item -Path $baseos_image -Force
}

$end_time = (Get-Date)
Write-Host " "
Write-Host " ********* TOTAL TIME : "  ($end_time - $start_time)  "********* "
exit
